<?php
if(!interface_exists('XClassFactory', false)){
	require_once(XFRAMEWORK_DIR.'/core/factory/XClassFactory.php');
}
if(!class_exists('XClassLoader', false)){
	require_once(XFRAMEWORK_DIR.'/core/context/XClassLoader.php');
}
class XAnnotationClassFactory implements XClassFactory{
	private static $instance = null;
	
	private function __construct() {
	}
	
	/** 
	 * @return XAnnotationClassFactory
	 */		
	public static function singleton() {
		if (!self::$instance) {
			self::$instance = new self;
		}
		return self::$instance;
	}
	
	/**
	 * @return object
	 */
	public function get($class, $scope = null, $args = array()){
		$loader = XClassLoader::loader($class);
		$annotation = XAnnotation::singleton($class);
		$classScope = $scope;
		if(is_null($classScope)){			
			$classScope = $annotation->get('Scope');
		}
		$params = $args;
		$constructor = $loader->reflection()->getConstructor();
		if(!is_null($constructor)
			&& !is_null($annotation->method("{$constructor->getName()}.Autowired"))){	
			$loader->setAutowireConstructParameters($annotation->method("{$constructor->getName()}.Autowired"));			
		}
		if($loader->inited()){
			return $loader->getInstance($this, $classScope, $params);
		}
		$methodAnnotations = $annotation->methodAnnotations();
		foreach($methodAnnotations as $method => $methodAnnotation){
			if(!$loader->hasMethod($method)){
				continue;
			}
			if(isset($methodAnnotation['Autowired'])
				&& $loader->isSetter($method)){
				$loader->addAutowireMethod($method, $methodAnnotation['Autowired']);
			}
			if(isset($methodAnnotation['PostConstruct'])){
				$loader->addPostConstructMethod($method, $methodAnnotation['PostConstruct']);
			}
			if(isset($methodAnnotation['PreDestroy'])){
				$loader->addPreDestroyMethod($method, $methodAnnotation['PreDestroy']);
			}
			if(isset($methodAnnotation['Required'])
				&& $loader->isSetter($method)){
				$loader->addRequiredSetter($method, $methodAnnotation['Required']);
			}
		}
		$propertyAnnotations = $annotation->propertyAnnotations();
		foreach($propertyAnnotations as $property => $propertyAnnotation){
			if(!$loader->hasProperty($property)){
				continue;
			}
			if(isset($propertyAnnotation['Autowired'])){
				$loader->addAutowireProperty($property, $propertyAnnotation['Autowired']);
			}
			if(isset($propertyAnnotation['Required'])){
				$loader->addRequiredProperties($property, $propertyAnnotation['Required']);
			}
		}
		$loader->setInited(true);
		return $loader->getInstance($this, $classScope, $params);
	}
	
	public function invokeArgs($object, $method, $args = array()){
		$class = get_class($object);
		$loader = XClassLoader::loader($class);
		if(!$loader->hasMethod($method)){
			throw new XMethodNotFoundException("method {$method} not exists in class {$class}");
		}
		return $loader->invokeArgs($object, $method, $args);
	}
}
?>